Rebuild GUI menus on a config-driven engine (guis.yml)#46
Conversation
|
You have used all of your free Bugbot PR reviews. To receive reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial. |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
🚧 Files skipped from review as they are similar to previous changes (4)
📝 WalkthroughWalkthroughA YAML-driven GUI subsystem is added with configurable rendering, actions, editor sessions, persistence, and placeholder handling. Legacy GUI entry points and the view-only enderchest command delegate to the new service, which is initialized during plugin startup. ChangesConfigurable GUI subsystem
Estimated code review effort: 4 (Complex) | ~70 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
src/main/java/dev/noah/perplayerkit/gui/GUI.java (1)
32-40: Don't keep the legacy state helpers as silent no-ops.If any legacy caller survives the migration, these methods now fail silently instead of surfacing the bad path.
src/main/java/dev/noah/perplayerkit/listeners/KitMenuCloseListener.javastill depends on this API, so I'd either remove the compatibility surface or deprecate it with an explicit failure/message while the old flow is being retired.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/dev/noah/perplayerkit/gui/GUI.java` around lines 32 - 40, These legacy state helper methods (setInspectTarget, getAndRemoveInspectTarget, removeKitDeletionFlag) currently no-op and silently hide callers like KitMenuCloseListener; update them to explicitly fail fast by throwing an UnsupportedOperationException (or at minimum log a clear warning and throw) with a message directing callers to the new API/flow so surviving callers are surfaced during testing, or alternatively implement the original behavior if backward compatibility must be preserved; ensure the exception message names the method (e.g., "GUI.setInspectTarget") and references KitMenuCloseListener migration guidance.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@src/main/java/dev/noah/perplayerkit/gui/configurable/ConfigurableGuiService.java`:
- Around line 266-287: renderPublicKitList currently only displays up to
slots.size() items, leaving PublicKit entries past that inaccessible; modify
renderPublicKitList to support pagination by reading a page index from
baseContext (e.g., "public_kit_page"), computing int start = page * slots.size()
and iterating from start to Math.min(start + slots.size(), publicKits.size())
when pulling from KitManager.get().getPublicKitList(), and render Prev/Next
controls (using applyVariant on dedicated control slots) that reopen the GUI
with updated "public_kit_page" in the GuiContext; alternatively, if you prefer
rejecting oversized configs, add a validation path that checks if
publicKits.size() > maxVisible (slots.size()) and logs/throws a clear config
validation error instead of silently truncating.
- Around line 1066-1077: resolveInt currently parses string values literally and
immediately returns defaultValue on NumberFormatException; instead, if the
string isn't a plain integer (e.g. contains a placeholder like "%slot%") or
parsing fails, try resolving the value from the GuiContext using the provided
fallbackContextKey before returning defaultValue. Update resolveInt to: when
rawValue is a String that fails Integer.parseInt, call
context.get(fallbackContextKey) (or the appropriate accessor on GuiContext) and
attempt to parse that result (or its toString()) to an int; also if rawValue is
null, try the same context lookup; only return defaultValue if both direct
parsing and the context-resolved value are unavailable or non-numeric. Use the
resolveInt function name and the fallbackContextKey/GuiContext symbols to locate
and modify the logic.
In `@src/main/resources/guis.yml`:
- Around line 48-49: The two label strings "<gray>● Left click to load
kit</gray>" and "<gray>● Right click to edit kit</gray>" are incorrect for the
enderchest menu; update them to say "enderchest" (e.g., "<gray>● Left click to
load enderchest</gray>" and "<gray>● Right click to edit enderchest</gray>") and
search the file for any other occurrences of "kit" in enderchest-related labels
(notably the occurrence around line 387 mentioned in the comment) and replace
them with the appropriate "enderchest" wording so the menu copy matches the
enderchest flow.
---
Nitpick comments:
In `@src/main/java/dev/noah/perplayerkit/gui/GUI.java`:
- Around line 32-40: These legacy state helper methods (setInspectTarget,
getAndRemoveInspectTarget, removeKitDeletionFlag) currently no-op and silently
hide callers like KitMenuCloseListener; update them to explicitly fail fast by
throwing an UnsupportedOperationException (or at minimum log a clear warning and
throw) with a message directing callers to the new API/flow so surviving callers
are surfaced during testing, or alternatively implement the original behavior if
backward compatibility must be preserved; ensure the exception message names the
method (e.g., "GUI.setInspectTarget") and references KitMenuCloseListener
migration guidance.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 9690b1f1-d594-404d-9794-884b4beec603
📒 Files selected for processing (7)
src/main/java/dev/noah/perplayerkit/PerPlayerKit.javasrc/main/java/dev/noah/perplayerkit/commands/EnderchestCommand.javasrc/main/java/dev/noah/perplayerkit/gui/GUI.javasrc/main/java/dev/noah/perplayerkit/gui/configurable/ConfigurableGuiService.javasrc/main/java/dev/noah/perplayerkit/gui/configurable/GuiConfigManager.javasrc/main/java/dev/noah/perplayerkit/gui/configurable/GuiContext.javasrc/main/resources/guis.yml
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/main/java/dev/noah/perplayerkit/gui/GUI.java`:
- Around line 85-90: The method ViewPublicKitMenu currently returns a
possibly-null Menu from ConfigurableGuiService.createPublicKitViewer; make this
contract explicit by annotating the method return type with a nullable
annotation (e.g., `@Nullable` from javax.annotation or org.jetbrains.annotations)
and add the corresponding import, keeping the current behavior (open if
non-null, return value unchanged). Reference: the method ViewPublicKitMenu, the
call to ConfigurableGuiService.createPublicKitViewer(Player, String), and the
Menu/Player types so reviewers can locate and update the signature and imports
accordingly.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 2dbd2f51-7acb-48c8-b2ea-f666affffc07
📒 Files selected for processing (3)
src/main/java/dev/noah/perplayerkit/PerPlayerKit.javasrc/main/java/dev/noah/perplayerkit/commands/kits/EnderchestCommand.javasrc/main/java/dev/noah/perplayerkit/gui/GUI.java
🚧 Files skipped from review as they are similar to previous changes (1)
- src/main/java/dev/noah/perplayerkit/PerPlayerKit.java
8e574ef to
1fe3d84
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (3)
src/main/java/dev/noah/perplayerkit/gui/configurable/ConfigurableGuiService.java (2)
912-922: Consider caching PlaceholderAPI availability check.
Bukkit.getPluginManager().getPlugin("PlaceholderAPI")is called on every text resolution. Since plugin presence doesn't change at runtime, caching this once during initialization would improve performance.Proposed enhancement
Add a field and initialize it in the constructor:
private final boolean hasPlaceholderApi; public ConfigurableGuiService(Plugin plugin) { this.plugin = plugin; this.guiConfigManager = new GuiConfigManager(plugin); this.hasPlaceholderApi = Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null; instance = this; }Then use it in
resolveText:private String resolveText(String value, Player viewer, GuiContext context) { if (value == null) { return null; } String resolved = resolvePlainValue(value, viewer, context); - if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) { + if (hasPlaceholderApi) { resolved = PlaceholderAPI.setPlaceholders(viewer, resolved); } return StyleManager.convertMiniMessage(resolved); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/dev/noah/perplayerkit/gui/configurable/ConfigurableGuiService.java` around lines 912 - 922, The resolveText method repeatedly calls Bukkit.getPluginManager().getPlugin("PlaceholderAPI") on every invocation; add a private final boolean field hasPlaceholderApi to the ConfigurableGuiService class, initialize it once in the constructor (ConfigurableGuiService(...)) by checking Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null, and then replace the runtime check in resolveText with a check of hasPlaceholderApi so PlaceholderAPI.setPlaceholders(viewer, resolved) is only called when hasPlaceholderApi is true.
924-935: PreferStringBuilderoverStringBufferfor single-threaded code.
StringBufferis synchronized, adding unnecessary overhead. Since this method runs on the main thread per call,StringBuilderis more appropriate.Proposed fix
private String resolvePlainValue(String value, Player viewer, GuiContext context) { Matcher matcher = PLACEHOLDER_PATTERN.matcher(value); - StringBuffer buffer = new StringBuffer(); + StringBuilder buffer = new StringBuilder(); while (matcher.find()) { String replacement = getPlaceholderValue(matcher.group(1), viewer, context); matcher.appendReplacement(buffer, Matcher.quoteReplacement(replacement)); } matcher.appendTail(buffer); return buffer.toString(); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/dev/noah/perplayerkit/gui/configurable/ConfigurableGuiService.java` around lines 924 - 935, resolvePlainValue currently uses synchronized StringBuffer via Matcher.appendReplacement/appendTail; replace it with an unsynchronized StringBuilder to avoid unnecessary overhead: keep PLACEHOLDER_PATTERN and the Matcher logic but change the loop to append the literal text between matches and the replacement into a StringBuilder using matcher.start()/matcher.end() (append the substring from the previous end index to matcher.start(), then append the replacement from getPlaceholderValue), track the last appended index, and after the loop append the remaining tail substring before returning builder.toString(); update the method resolvePlainValue accordingly.src/main/java/dev/noah/perplayerkit/gui/configurable/GuiConfigManager.java (1)
21-26: Consider handling missing or malformed configuration more explicitly.If
guis.ymlexists but contains invalid YAML,YamlConfiguration.loadConfiguration()returns an empty configuration without throwing. This could cause silent failures downstream when GUI sections are requested. Consider logging a warning when the file exists but produces an empty/invalid configuration.Proposed enhancement
public final void load() { if (!guiConfigFile.exists()) { plugin.saveResource("guis.yml", false); } guiConfiguration = YamlConfiguration.loadConfiguration(guiConfigFile); + if (guiConfiguration.getKeys(false).isEmpty()) { + plugin.getLogger().warning("guis.yml appears to be empty or invalid"); + } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/dev/noah/perplayerkit/gui/configurable/GuiConfigManager.java` around lines 21 - 26, The load() method currently calls YamlConfiguration.loadConfiguration(guiConfigFile) but doesn’t detect when the file exists yet yields an empty/invalid configuration; update load() to check the loaded guiConfiguration for emptiness (e.g., no top-level keys/sections) after YamlConfiguration.loadConfiguration(guiConfigFile) and if empty: log a warning via the plugin logger including the file name (guiConfigFile) and that the YAML appears invalid, then either attempt to restore the default with plugin.saveResource("guis.yml", true) or copy the bundled default into place and re-load; reference the existing symbols load(), guiConfigFile, guiConfiguration, plugin.saveResource and YamlConfiguration.loadConfiguration when implementing this check and recovery.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In
`@src/main/java/dev/noah/perplayerkit/gui/configurable/ConfigurableGuiService.java`:
- Around line 912-922: The resolveText method repeatedly calls
Bukkit.getPluginManager().getPlugin("PlaceholderAPI") on every invocation; add a
private final boolean field hasPlaceholderApi to the ConfigurableGuiService
class, initialize it once in the constructor (ConfigurableGuiService(...)) by
checking Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null, and then
replace the runtime check in resolveText with a check of hasPlaceholderApi so
PlaceholderAPI.setPlaceholders(viewer, resolved) is only called when
hasPlaceholderApi is true.
- Around line 924-935: resolvePlainValue currently uses synchronized
StringBuffer via Matcher.appendReplacement/appendTail; replace it with an
unsynchronized StringBuilder to avoid unnecessary overhead: keep
PLACEHOLDER_PATTERN and the Matcher logic but change the loop to append the
literal text between matches and the replacement into a StringBuilder using
matcher.start()/matcher.end() (append the substring from the previous end index
to matcher.start(), then append the replacement from getPlaceholderValue), track
the last appended index, and after the loop append the remaining tail substring
before returning builder.toString(); update the method resolvePlainValue
accordingly.
In `@src/main/java/dev/noah/perplayerkit/gui/configurable/GuiConfigManager.java`:
- Around line 21-26: The load() method currently calls
YamlConfiguration.loadConfiguration(guiConfigFile) but doesn’t detect when the
file exists yet yields an empty/invalid configuration; update load() to check
the loaded guiConfiguration for emptiness (e.g., no top-level keys/sections)
after YamlConfiguration.loadConfiguration(guiConfigFile) and if empty: log a
warning via the plugin logger including the file name (guiConfigFile) and that
the YAML appears invalid, then either attempt to restore the default with
plugin.saveResource("guis.yml", true) or copy the bundled default into place and
re-load; reference the existing symbols load(), guiConfigFile, guiConfiguration,
plugin.saveResource and YamlConfiguration.loadConfiguration when implementing
this check and recovery.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 93237830-abcf-436c-9a09-d1d43b4d6004
📒 Files selected for processing (7)
src/main/java/dev/noah/perplayerkit/PerPlayerKit.javasrc/main/java/dev/noah/perplayerkit/commands/kits/EnderchestCommand.javasrc/main/java/dev/noah/perplayerkit/gui/GUI.javasrc/main/java/dev/noah/perplayerkit/gui/configurable/ConfigurableGuiService.javasrc/main/java/dev/noah/perplayerkit/gui/configurable/GuiConfigManager.javasrc/main/java/dev/noah/perplayerkit/gui/configurable/GuiContext.javasrc/main/resources/guis.yml
🚧 Files skipped from review as they are similar to previous changes (4)
- src/main/resources/guis.yml
- src/main/java/dev/noah/perplayerkit/gui/GUI.java
- src/main/java/dev/noah/perplayerkit/PerPlayerKit.java
- src/main/java/dev/noah/perplayerkit/gui/configurable/GuiContext.java
The configurable GUI engine (added next) lives in gui.configurable and needs the title-update capability check and in-place title updates. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Bukkit-free building blocks for the configurable GUI engine:
- GuiSlots parses slot declarations (numbers, ranges incl. descending,
lists), order-preserving and bounds-checked against the menu size
- GuiText expands %lang:<key>% (lang lookup applies the message's own
{token} placeholders) and %token% context values, leaving unknown
tokens for PlaceholderAPI; resolveInt expands placeholders in numeric
arguments so "slot: %slot%" means the context slot
- GuiContext is the immutable value bag menus are opened with
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Menus missing from the user's guis.yml fall back to the copy bundled in the jar, per GUI (not per key), so shipping new menus never strands old installs. A file with an older config-version is archived to guis.yml.v<N>.bak and regenerated with a warning: a schema bump can rename components or actions, and a stale file would otherwise shadow the bundled menus wholesale and half-work. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The kit room GUI is about to become config-driven; callers need the storage bound to clamp page indexes instead of running into the fixed five-page list's IndexOutOfBoundsException. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ConfigurableGuiService builds every menu from guis.yml: elements carry slots, items, permissions, and click actions; components (kit-slot selectors, pagination arrows, public-kit list, item-data regions, kit room categories) render plugin data into config-declared positions; variants give per-state items/actions with a named -> default -> element fallback per key. All default text routes through the lang system via %lang:key% placeholders, so the bundled translations apply and owners can restyle any menu; PlaceholderAPI works where installed. Repeated menu blocks (armor indicators, editor tools) are shared as YAML anchors, covered by a test proving YamlConfiguration flattens merge keys. Editor persistence keeps the session model the old GUI class proved out: an EditorSession registered on open records the data slots (from the menu's own config) and expected size; it is flushed by InventoryCloseEvent or before opening the next menu, since canvas redraw navigation reuses the open inventory and never fires a close event. Saves read the closing Bukkit inventory directly. Delete actions suppress the close-save even when the delete found nothing — the menu still shows stale contents and saving them would resurrect a kit another admin deleted. max-kits pagination is a main-menu component: kit slot numbers derive from the page in the open context, arrows appear only where valid, and back buttons return to the page a kit lives on (or the remembered page), while /kit always starts at page 1. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
GUI becomes a thin facade over ConfigurableGuiService, keeping the entry points commands and listeners call; KitMenuCloseListener hands closing inventories to the service's editor sessions; the view-only enderchest and plugin startup wire in the service. EditorSaver, GuiMenuFactory, and GuiLayoutUtils are superseded by the engine and guis.yml. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1fe3d84 to
850f224
Compare
|
@coderabbitai full review |
✅ Action performedFull review finished. Your plan includes PR reviews subject to rate limits. More reviews will be available in 58 minutes. |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/test/java/dev/noah/perplayerkit/gui/configurable/BundledGuisConfigTest.java (1)
27-32: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueClose the resource stream after loading the YAML.
The
InputStreamfromgetResourceAsStreamis wrapped in anInputStreamReaderbut never closed. While the JVM will clean up at test shutdown, using try-with-resources is best practice and prevents resource leak warnings in CI.♻️ Proposed refactor
`@BeforeAll` static void load() { - var stream = BundledGuisConfigTest.class.getClassLoader().getResourceAsStream("guis.yml"); - assertNotNull(stream, "guis.yml missing from resources"); - config = YamlConfiguration.loadConfiguration(new InputStreamReader(stream, StandardCharsets.UTF_8)); + try (var stream = BundledGuisConfigTest.class.getClassLoader().getResourceAsStream("guis.yml")) { + assertNotNull(stream, "guis.yml missing from resources"); + config = YamlConfiguration.loadConfiguration(new InputStreamReader(stream, StandardCharsets.UTF_8)); + } }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/test/java/dev/noah/perplayerkit/gui/configurable/BundledGuisConfigTest.java` around lines 27 - 32, Update the `@BeforeAll` load() method to wrap the resource InputStreamReader in try-with-resources, ensuring the stream from getResourceAsStream is closed after YamlConfiguration.loadConfiguration completes while preserving the existing missing-resource assertion.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/main/java/dev/noah/perplayerkit/gui/configurable/ConfigurableGuiService.java`:
- Around line 487-508: Implement handling for public kits beyond the configured
slot count in renderPublicKitList: either add pagination/navigation so every kit
can be loaded and viewed, or explicitly reject configurations where publicKits
exceeds slots and prevent startup/use with a clear validation error. Ensure the
chosen behavior covers load, view, and edit access rather than only logging a
warning.
In `@src/main/java/dev/noah/perplayerkit/gui/configurable/GuiSlots.java`:
- Around line 88-91: Limit range expansion in the slot-parsing logic before
entering the loop in GuiSlots:parse (or the helper containing the shown loop),
rejecting ranges whose size exceeds a safe maximum. Calculate the range length
using long arithmetic to avoid overflow, validate both endpoints and the
computed size, then iterate only after validation so oversized or overflowing
ranges cannot populate the LinkedHashSet.
---
Nitpick comments:
In
`@src/test/java/dev/noah/perplayerkit/gui/configurable/BundledGuisConfigTest.java`:
- Around line 27-32: Update the `@BeforeAll` load() method to wrap the resource
InputStreamReader in try-with-resources, ensuring the stream from
getResourceAsStream is closed after YamlConfiguration.loadConfiguration
completes while preserving the existing missing-resource assertion.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 339af013-4d66-4d8d-8124-78b9587a33f4
📒 Files selected for processing (18)
src/main/java/dev/noah/perplayerkit/KitRoomDataManager.javasrc/main/java/dev/noah/perplayerkit/PerPlayerKit.javasrc/main/java/dev/noah/perplayerkit/commands/kits/EnderchestCommand.javasrc/main/java/dev/noah/perplayerkit/gui/GUI.javasrc/main/java/dev/noah/perplayerkit/gui/GuiCompat.javasrc/main/java/dev/noah/perplayerkit/gui/GuiLayoutUtils.javasrc/main/java/dev/noah/perplayerkit/gui/GuiMenuFactory.javasrc/main/java/dev/noah/perplayerkit/gui/configurable/ConfigurableGuiService.javasrc/main/java/dev/noah/perplayerkit/gui/configurable/EditorSession.javasrc/main/java/dev/noah/perplayerkit/gui/configurable/GuiConfigManager.javasrc/main/java/dev/noah/perplayerkit/gui/configurable/GuiContext.javasrc/main/java/dev/noah/perplayerkit/gui/configurable/GuiSlots.javasrc/main/java/dev/noah/perplayerkit/gui/configurable/GuiText.javasrc/main/java/dev/noah/perplayerkit/listeners/KitMenuCloseListener.javasrc/main/resources/guis.ymlsrc/test/java/dev/noah/perplayerkit/gui/configurable/BundledGuisConfigTest.javasrc/test/java/dev/noah/perplayerkit/gui/configurable/GuiSlotsTest.javasrc/test/java/dev/noah/perplayerkit/gui/configurable/GuiTextTest.java
💤 Files with no reviewable changes (2)
- src/main/java/dev/noah/perplayerkit/gui/GuiMenuFactory.java
- src/main/java/dev/noah/perplayerkit/gui/GuiLayoutUtils.java
🚧 Files skipped from review as they are similar to previous changes (2)
- src/main/java/dev/noah/perplayerkit/commands/kits/EnderchestCommand.java
- src/main/resources/guis.yml
- GuiSlots rejects ranges wider than any menu before expanding them; a typo like "0-999999999" warned per-slot after ballooning the set (and could overflow at the int boundary) instead of being dropped outright - The public kit list gets 27 slots (the row above was filler glass); kits beyond the configured slots are still capped with a warning — the old code rendered them over the footer buttons instead - The enderchest editor's clear button says CLEAR ENDERCHEST, not CLEAR KIT (label carried over from the kit editor, also flagged on the original branch) - Close the guis.yml resource stream in the bundled-config test Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Summary
Rebuilds the GUI layer on a config-driven engine. Every menu the plugin opens is defined in a new
guis.yml(layout, items, text, click actions), interpreted byConfigurableGuiService; behavior stays in code as named components and action types the config refers to.GUIbecomes a thin facade so all existing entry points keep working.This branch was rewritten from scratch on top of current main — the original version predated i18n, max-kits pagination, and the editor save-during-redraw fix, and rebasing it would have reverted those. What the rework preserves and how:
EditorSessionregistered on open, flushed byInventoryCloseEventor before opening the next menu (canvas redraw navigation reuses the open inventory and never fires a close event). Saves read the closing Bukkit inventory directly; the data slots come from the menu's own config, in declared order.%lang:key%placeholders, so the 14 bundled translations still apply; server owners can restyle or hardcode any text per menu. PlaceholderAPI placeholders work anywhere when installed./kitalways starts at page 1.guis.ymlcarries aconfig-version; menus missing from a user's file fall back per-GUI to the bundled copy, and a file with an older schema is archived toguis.yml.v<N>.bakand regenerated with a warning instead of half-working.YamlConfigurationflattens merge keys.Review process
The diff went through two multi-agent review passes with fixes applied:
Notable catches folded in: a failed inspect-delete no longer resurrects a kit another admin deleted; kit-room page indexes clamp instead of throwing
IndexOutOfBoundsException; admin feedback paths and click-sound/keyboard-click semantics match the old menus;open-guiactions forward only explicitly declared context keys.Testing
slot: "%slot%"), and invariants on the bundled config (41 kit / 27 enderchest / 45 kit-room data slots, template-anchor flattening).guis.ymlextraction, per-GUI defaults fallback, and the v1→v2 archive-and-regenerate migration end-to-end.max-kits > 9). Recommended before merge — headless verification can't click menus.🤖 Generated with Claude Code
Summary by CodeRabbit
guis.yml, covering main kit hub, kit/public kit editors, enderchest editing, view-only enderchest, kit room browsing, public kit browser/viewer, and admin inspect menus.